﻿using System.Security.Cryptography;

namespace Basic.Base.Encryption;

public sealed class BaseRSAEncryption : IAsymmetricAlgorithm
{
    private readonly RSAEncryptionPadding EncryptionPadding = RSAEncryptionPadding.OaepSHA256;
    private readonly RSASignaturePadding SignaturePadding = RSASignaturePadding.Pkcs1;
    private readonly HashAlgorithmName HashAlgorithm = HashAlgorithmName.SHA256;

    private RSA _provider;

    private byte[] PublicKey;
    private byte[] PrivateKey;

    private string PublicKeyStr;
    private string PrivateKeyStr;

    public BaseRSAEncryption()
    {

    }

    public BaseRSAEncryption(string publicKey, string privateKey)
    {
        if (publicKey == null && privateKey == null)
            throw new ArgumentNullException("publicKey和privateKey不能同时为null!");

        if (!string.IsNullOrWhiteSpace(publicKey))
        {
            PublicKeyStr = publicKey;
            PublicKey = Convert.FromBase64String(publicKey);
        }
        if (!string.IsNullOrWhiteSpace(privateKey))
        {
            PrivateKeyStr = privateKey;
            PrivateKey = Convert.FromBase64String(privateKey);
        }
        Init();
    }

    public BaseRSAEncryption(byte[] publicKey, byte[] privateKey)
    {
        if (publicKey == null && privateKey == null)
            throw new ArgumentNullException("publicKey和privateKey不能同时为null!");

        if (publicKey?.Length > 0)
        {
            PublicKey = publicKey;
            PublicKeyStr = Convert.ToBase64String(publicKey);
        }
        if (privateKey?.Length > 0)
        {
            PrivateKey = privateKey;
            PrivateKeyStr = Convert.ToBase64String(privateKey);
        }
        Init();
    }

    private RSA Init()
    {
        _provider = RSA.Create();

        if (PublicKey?.Length > 0)
            _provider.ImportRSAPublicKey(PublicKey, out int num);

        if (PrivateKey?.Length > 0)
            _provider.ImportRSAPrivateKey(PrivateKey, out int num);

        return _provider;
    }

    #region 数据流加解密

    /// <summary>
    /// 加密
    /// </summary>
    /// <param name="rawData"></param>
    /// <returns></returns>
    public byte[] Encrypt(byte[] rawData)
    {
        return _provider.Encrypt(rawData, EncryptionPadding);
    }

    /// <summary>
    /// 解密
    /// </summary>
    /// <param name="encryptionData"></param>
    /// <returns></returns>
    public byte[] Decrypt(byte[] encryptionData)
    {
        return _provider.Decrypt(encryptionData, EncryptionPadding);
    }

    /// <summary>
    /// 密文签名
    /// </summary>
    /// <param name="encryptionData">密文</param>
    /// <returns>签名</returns>
    public byte[] SignData(byte[] encryptionData)
    {
        return _provider.SignData(encryptionData, HashAlgorithm, SignaturePadding);
    }

    /// <summary>
    /// 签名验证
    /// </summary>
    /// <param name="encryptionData">密文</param>
    /// <param name="signData">签名</param>
    /// <returns></returns>
    public bool VerifyData(byte[] encryptionData, byte[] signData)
    {
        return _provider.VerifyData(encryptionData, signData, HashAlgorithm, SignaturePadding);
    }

    #endregion

    #region 字符串加解密

    /// <summary>
    /// 加密
    /// </summary>
    /// <param name="rawString"></param>
    /// <returns></returns>
    public string Encrypt(string rawString)
    {
        var encryptionData = Encrypt(Encoding.UTF8.GetBytes(rawString));
        return Convert.ToBase64String(encryptionData);
    }

    /// <summary>
    /// 解密
    /// </summary>
    /// <param name="encryptionString"></param>
    /// <returns></returns>
    public string Decrypt(string encryptionString)
    {
        var rawData = Decrypt(Convert.FromBase64String(encryptionString));
        return Encoding.UTF8.GetString(rawData);
    }

    /// <summary>
    /// 密文签名
    /// </summary>
    /// <param name="encryptionData">密文</param>
    /// <returns>签名</returns>
    public string SignData(string encryptionData)
    {
        byte[] encryptionBytes = Convert.FromBase64String(encryptionData);
        byte[] signBytes = _provider.SignData(encryptionBytes, HashAlgorithm, SignaturePadding);
        return Convert.ToBase64String(signBytes);
    }

    /// <summary>
    /// 签名验证
    /// </summary>
    /// <param name="encryptionData">密文</param>
    /// <param name="signData">签名</param>
    /// <returns></returns>
    public bool VerifyData(string encryptionData, string signData)
    {
        byte[] encryptionBytes = Convert.FromBase64String(encryptionData);
        byte[] signBytes = Convert.FromBase64String(signData);
        return _provider.VerifyData(encryptionBytes, signBytes, HashAlgorithm, SignaturePadding);
    }


    #endregion


    public (string PublicKey, string PrivateKey) GenerateKey() => BaseRSAEncryption.GenerateKeys();

    #region static

    public static (string PublicKey, string PrivateKey) GenerateKeys()
    {
        using RSA provider = RSA.Create();
        byte[] publicKeyBytes = provider.ExportRSAPublicKey();
        byte[] privateKeyBytes = provider.ExportRSAPrivateKey();
        return (Convert.ToBase64String(publicKeyBytes), Convert.ToBase64String(privateKeyBytes));
    }

    #endregion

    #region Dispose()
    private bool disposedValue;

    private void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                _provider?.Dispose();
            }
            _provider = null;
            disposedValue = true;
        }
    }

    public void Dispose()
    {
        // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }

    #endregion

}